﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SCG.Prism;
using SCG.SolarVengeanceEngine;
using System.Net;
using System.IO;

namespace SCG.SolarVengeance
{
    public partial class LobbyPage : BasePage
    {
        //constructors
        public LobbyPage()
            : base()
        {
            InitializeComponent();
        }

        //initialization
        public override void Initialize()
        {
            if (MainForm.Prism.LoggedIn)
                txtChat.Focus();
            else
                txtUserName.Focus();
        }

        //did we host the game?
        public bool HostedGame { get; set; }

        //PrismClient event handlers
        public void ConnectSuccessful()
        {
            if (_loggingInNew)
                MainForm.Prism.LoginNew(_user);
            else
                MainForm.Prism.Login(txtUserName.Text, txtPassword.Text);
            MainForm.Settings.Set("Host", cmbServers.Text);
            MainForm.Settings.SaveSettings();
        }

        //connect failed
        public void ConnectFailure(string message)
        {
            MessageBox.Show("Connect Failure: " + message);
            EnableControls(pnlToolbar, 1, true);
        }

        //disconnected
        public void Disconnected()
        {
            ShowControls(pnlToolbar, 1, true);
            btnRankings.Visible = false;
            btnBrainDuel.Visible = false;
            EnableControls(pnlToolbar, 1, true);
            MessageBox.Show("You've been Disconnected from PrismServer.");
        }

        //login error
        public void LoginError(string message)
        {
            MessageBox.Show("Login Failure: " + message);
            EnableControls(pnlToolbar, 1, true);
        }

        //login successful
        public void LoginSuccessful()
        {
            txtChat.Focus();
            ShowControls(pnlToolbar, 1, false);
            btnRankings.Visible = true;
            btnBrainDuel.Visible = true;
            MainForm.PersistStarLordSettings();
            lblLoading.Visible = true;
            lblLoading.Refresh();
            MainForm.Prism.CustomCommand("SVBrainRankings", "");
        }

        //scenarios recieved
        private bool _receivedScenarios = false;
        public void ScenariosReceived()
        {
            _receivedScenarios = true;
            lblLoading.Visible = false;
            btnCreateGame.Visible = true;
        }

        //someone joined the lobby
        public void UserJoined(PrismUser user)
        {
            int idx = -1;
            if (_imageMapper.ContainsKey(user.UserName))
                idx = _imageMapper[user.UserName];
            else if (user.Glyph != null)
            {
                images.Images.Add(user.Glyph);
                idx = images.Images.Count - 1;
                _imageMapper[user.UserName] = idx;
            }

            ListViewItem lvi = lvStarLords.Items.Add(user.UserName);
            lvi.SubItems.Add(user.GetRating("SV").ToString("N0"));
            lvi.Tag = user;
            lvi.ImageIndex = idx;
        }

        //user info (rating) changed
        public void UpdateUserInfo(PrismUser user)
        {
            foreach (ListViewItem lvi in lvStarLords.Items)
            {
                PrismUser p = lvi.Tag as PrismUser;
                if (p.UserName == user.UserName)
                {
                    lvi.Tag = user;
                    lvi.SubItems[1].Text = user.GetRating("SV").ToString("N0");
                }
            }
        }

        //someone left the lobby
        public void UserLeft(PrismUser user)
        {
            for (int n = lvStarLords.Items.Count - 1; n >= 0; n--)
            {
                ListViewItem lvi = lvStarLords.Items[n];
                PrismUser pu = lvi.Tag as PrismUser;
                if (pu.UserName == user.UserName)
                {
                    lvStarLords.Items.Remove(lvi);
                    return;
                }
            }
        }

        //chat message
        public void Chat(string s, PrismUser user)
        {
            txtChatLog.Text += user.UserName + ": " + s + Environment.NewLine;
        }

        //room (game) added
        public void RoomAdded(string roomName)
        {
            if (!_receivedScenarios)
                return;
            string[] tokens = roomName.Split(';');
            if (tokens.Length >= 4)
            {
                string scenarioName = tokens[0];

                //avoid adding rooms if the player doesn't have the custom scenario file
                if (MainForm.TitlePage.FindScenario(scenarioName) == null)
                    return;

                string creator = tokens[1];
                string humanPlayers = tokens[2];
                string brainPlayers = tokens[3];
                string description = scenarioName + " Host=" + creator + ", " + humanPlayers + " Humans";
                if (brainPlayers != "0")
                    description += ", ";
                if (brainPlayers == "1")
                    description += "1 Brain";
                else if (brainPlayers != "0")
                    description += brainPlayers + " Brains";
                ListViewItem lvi = lvGames.Items.Add(description);
                RoomInfo ri = new RoomInfo();
                ri.RoomName = roomName;
                ri.GuestCount = 1;
                ri.Maximum = Int32.Parse(humanPlayers);
                lvi.Tag = ri;
                lvi.SubItems.Add("");
                RoomCountChanged(roomName, 1);

                //authorized?
                if (MainForm.GetAuthorizedScenario(scenarioName) == null)
                    lvi.StateImageIndex = 2;

                //generate the preview image
                int idx = 4;
                Scenario scen = MainForm.TitlePage.FindScenario(scenarioName);
                foreach (ScenarioParameter sp in scen.Parameters)
                    sp.Value = Int32.Parse(tokens[idx++]);
                Image img = ScenarioPreviewGenerator.GeneratePreview(scen, 60, 60);
                imagesGames.Images.Add(img);
                lvi.ImageIndex = imagesGames.Images.Count - 1;
            }
        }

        //room (game) removed
        public void RoomRemoved(string roomName)
        {
            for (int n = lvGames.Items.Count - 1; n >= 0; n--)
            {
                RoomInfo ri = lvGames.Items[n].Tag as RoomInfo;
                if (ri.RoomName == roomName)
                {
                    lvGames.Items.RemoveAt(n);
                    return;
                }
            }
        }

        //joined a new room
        private bool _requestedRooms = false;
        public void JoinRoom(string roomName)
        {
            lvStarLords.Items.Clear();
            if (roomName == "Lobby")
            {
                lblRoom.Text = "You are in the Lobby";
                btnWithdrawGame.Visible = false;
            }
            else
            {
                lblRoom.Text = "You are in the Game Waiting Room";
                btnWithdrawGame.Visible = true;
            }
            if (!_requestedRooms)
            {
                _requestedRooms = true;
                MainForm.Prism.RequestRoomList();
            }
        }

        //clear rooms
        public void ClearRooms()
        {
            lvGames.Items.Clear();
        }

        //number of players in room changed
        public void RoomCountChanged(string roomName, int count)
        {
            ListViewItem lvi = FindRoom(roomName);
            if (lvi != null)
            {
                RoomInfo ri = lvi.Tag as RoomInfo;
                lvi.SubItems[1].Text = count + "/" + ri.Maximum;
                if (count >= ri.Maximum)
                    LockRoom(roomName);
            }
        }

        //Lock the room
        public void LockRoom(string roomName)
        {
            ListViewItem lvi = FindRoom(roomName);
            if (lvi != null)
                lvi.StateImageIndex = 1;
        }

        //find listview item that corresponds to room
        private ListViewItem FindRoom(string roomName)
        {
            foreach (ListViewItem lvi in lvGames.Items)
            {
                RoomInfo ri = lvi.Tag as RoomInfo;
                if (ri.RoomName == roomName)
                    return lvi;
            }
            return null;
        }

        //create an account
        private void btnCreateAccount_Click(object sender, EventArgs e)
        {
            AccountDetailsForm frmCreateAccount = new AccountDetailsForm();
            if (frmCreateAccount.ShowDialog(this) == DialogResult.OK)
            {
                _user = frmCreateAccount.PrismUser;
                _loggingInNew = true;
                EnableControls(pnlToolbar, 1, false);
                if (MainForm.Prism.Connected)
                    ConnectSuccessful();
                else
                    ConnectToServer();
            }
        }

        //private members
        private PrismUser _user;
        private bool _loggingInNew = false;
        private Dictionary<string, int> _imageMapper = new Dictionary<string, int>();

        //login
        private void btnLogin_Click(object sender, EventArgs e)
        {
            Login();
        }

        private void Login()
        {
            _loggingInNew = false;
            EnableControls(pnlToolbar, 1, false);
            if (MainForm.Prism.Connected)
                ConnectSuccessful();
            else
                ConnectToServer();
        }

        //connect to PrismServer
        private void ConnectToServer()
        {
            string[] tokens = cmbServers.Text.Split(' ');
            if (tokens.Length == 0)
                return;
            MainForm.Prism.Host = tokens[0].Trim();
            MainForm.Prism.Connect();
        }

        //enable login button?
        private void txtUserName_TextChanged(object sender, EventArgs e)
        {
            btnLogin.Enabled = txtUserName.Text != "" && txtPassword.Text != "";
        }

        //exit the lobby
        private void btnExit_Click(object sender, EventArgs e)
        {
            MainForm.ShowPage(Pages.Title);
        }

        //enable send button?
        private void txtChat_TextChanged(object sender, EventArgs e)
        {
            btnSendChat.Enabled = txtChat.Text != "" && MainForm.Prism.LoggedIn;
        }

        //send chat
        private void btnSendChat_Click(object sender, EventArgs e)
        {
            SendChat();
        }

        private void txtChat_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Return)
                SendChat();
        }

        private void SendChat()
        {
            string s = txtChat.Text;
            MainForm.Prism.SendChat(s);
            txtChatLog.Text += MainForm.Prism.ThisUser.UserName + ": " + s + Environment.NewLine;
            txtChat.Text = "";
            btnSendChat.Enabled = false;
        }

        //return key for password field
        private void txtPassword_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Return)
                if (txtUserName.Text != "" && txtPassword.Text != "" && btnLogin.Enabled)
                    Login();
        }

        //create a new game
        private void btnCreateGame_Click(object sender, EventArgs e)
        {
            HostedGame = true;
            MainForm.ShowPage(Pages.SetupMulti);
        }

        //dynamic column widths
        private void lvStarLords_SizeChanged(object sender, EventArgs e)
        {
            colStarLord.Width = lvStarLords.Width - System.Windows.Forms.SystemInformation.VerticalScrollBarWidth - 4 - 80;
        }

        private void lvGames_SizeChanged(object sender, EventArgs e)
        {
            colGame.Width = lvGames.Width - System.Windows.Forms.SystemInformation.VerticalScrollBarWidth - 4 - 80;
        }

        //return to the lobby
        private void btnWithdrawGame_Click(object sender, EventArgs e)
        {
            MainForm.Prism.EnterRoom("Lobby");
        }

        //clicked a game
        private void lvGames_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lvGames.SelectedItems.Count != 1)
            {
                btnJoinGame.Visible = false;
                return;
            }
            ListViewItem lvi = lvGames.SelectedItems[0];
            RoomInfo ri = lvi.Tag as RoomInfo;
            btnJoinGame.Visible = ri.RoomName != MainForm.Prism.RoomName && lvi.StateImageIndex != 1;
        }

        //Join game
        private void btnJoinGame_Click(object sender, EventArgs e)
        {
            if (lvGames.SelectedItems.Count != 1)
                return;
            HostedGame = false;
            ListViewItem lvi = lvGames.SelectedItems[0];

            if (lvi.StateImageIndex == 2)
                if (MessageBox.Show("This is a custom Scenario, do you wish to join?", "Custom Scenario", MessageBoxButtons.YesNo) == DialogResult.No)
                    return;

            RoomInfo ri = lvi.Tag as RoomInfo;
            MainForm.Prism.EnterRoom(ri.RoomName);
            btnJoinGame.Visible = false;
        }

        //page load - obtain list of servers
        private void LobbyPage_Load(object sender, EventArgs e)
        {
            cmbServers.Items.Add("localhost (Dev Server)");
            try
            {
                WebRequest request = WebRequest.Create("http://www.siliconcommandergames.com/asp/ActivePrismServers.aspx");
                WebResponse response = request.GetResponse();
                Stream s = response.GetResponseStream();
                StreamReader sr = new StreamReader(s);
                string content = sr.ReadToEnd();
                sr.Close();
                response.Close();
                int pos = content.IndexOf("lblServers\">");
                content = content.Substring(pos + 12);
                pos = content.IndexOf("<");
                content = content.Substring(0, pos);
                string[] tokens = content.Split('|');
                if (tokens.Length > 0)
                {
                    int n = 0;
                    while (n < tokens.Length)
                    {
                        string IP = tokens[n++];
                        if (IP == "")
                            break;
                        string machineName = tokens[n++];
                        string entry = IP + " (" + machineName + ")";
                        cmbServers.Items.Add(entry);
                    }
                }

                //select the last entry (if remembered)
                string lastEntry = MainForm.Settings.Get("Host", "");
                if (lastEntry != "")
                    if (cmbServers.Items.Contains(lastEntry))
                        cmbServers.SelectedItem = lastEntry;
                if (cmbServers.SelectedIndex == -1)
                    if (cmbServers.Items.Count > 0)
                        cmbServers.SelectedIndex = 0;
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error obtaining list of PrismServers: " + ex.Message);
            }
        }

        //brain duels
        private void btnBrainDuel_Click(object sender, EventArgs e)
        {
            MainForm.ShowPage(Pages.BrainDuel);
        }

        //close Star Lord rankings
        private void btnCloseRankings_Click(object sender, EventArgs e)
        {
            pnlRankings.Visible = false;
        }

        //resize column
        private void lvRankings_SizeChanged(object sender, EventArgs e)
        {
            colRankedStarLord.Width = lvRankings.Width - 4 - System.Windows.Forms.SystemInformation.VerticalScrollBarWidth - colRank.Width - colRankedRating.Width;
        }

        //view star lord rankings interface
        private void btnRankings_Click(object sender, EventArgs e)
        {
            pnlRankings.Visible = true;
            lvRankings.Items.Clear();
            imagesRankings.Images.Clear();
            MainForm.Prism.CustomCommand("SVStarLordRankings", "");
        }

        //star lord rankings received
        public void StarLordRankingsRecieved(List<PrismUser> users)
        {
            int rank = 1;
            foreach (PrismUser user in users)
            {
                ListViewItem lvi = lvRankings.Items.Add(rank + ".");
                rank++;
                lvi.SubItems.Add(user.UserName);
                lvi.SubItems.Add(user.GetRating("SV").ToString("N0"));
                if (user.Glyph != null)
                {
                    imagesRankings.Images.Add(user.Glyph);
                    lvi.ImageIndex = imagesRankings.Images.Count - 1;
                }
            }
        }
    }
}
